package mt.testcomm;

import static org.junit.Assert.*;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Random;

import mt.Order;
import mt.comm.ClientSideMessage;
import mt.comm.CommunicationsClient;
import mt.comm.CommunicationsServer;
import mt.comm.ServerSideMessage.Type;

import org.junit.Test;
	/**
	 * Test the interaction between the server and multiple(two) clients
	 * 
	 * @author Nuno Santos
	 *
	 */
public class TestServerClientsCommunication {

	private String nameOne = "NameOne";
	private String nameTwo = "NameTwo";
	private Random random = new Random();
	
	private CommunicationsServer server;
	private CommunicationsClient clientOne;
	private CommunicationsClient clientTwo;
	
	/**
	 * Creates the server and connects the two clients
	 */
	
	public void constructServerClient(){
		int port = random.nextInt(100);
		
		server = new CommunicationsServer(port);
		clientOne = new CommunicationsClient(port);
		clientTwo = new CommunicationsClient(port);
		
		server.start();
		
		assertFalse(server.clientIsConnected(nameOne));
		assertFalse(server.clientIsConnected(nameTwo));
		assertFalse(server.hasNextMessage());
		
		try {
			clientOne.connect("localhost", nameOne);
			
			Thread.sleep(500);
			assertTrue(server.clientIsConnected(nameOne));
			assertFalse(server.clientIsConnected(nameTwo));
			
			clientTwo.connect("localhost", nameTwo);
			
			Thread.sleep(500);
			assertTrue(server.clientIsConnected(nameOne));
			assertTrue(server.clientIsConnected(nameTwo));
			
			Thread.sleep(500);
			assertTrue(server.hasNextMessage());
			assertEquals(server.getNextMessage().getType(), Type.CONNECTED);
			assertEquals(server.getNextMessage().getType(), Type.CONNECTED);
			
			Thread.sleep(100);
			assertFalse(server.hasNextMessage());
			
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		
	}
	
	/**
	 * Test if the connection server/clients was well succeeded
	 */
	@Test
	public void testServerClientConnections() {
		constructServerClient();
	}
	
	/**
	 * Tests if the server receives messages from the clients and knows from which they are
	 */
	@Test
	public void clientToServerMessage(){
		Order orderOne = Order.createBuyOrder(nameOne, "EDP", 20, 1);
		Order orderTwo = Order.createBuyOrder(nameTwo, "EDP", 20, 1);
		 
		constructServerClient();
		
		try {
			
			clientOne.sendOrder(orderOne);
			Thread.sleep(500);
			clientTwo.sendOrder(orderTwo);
			

			Thread.sleep(500);
			assertTrue(server.hasNextMessage());
			assertEquals(server.getNextMessage().getSenderNickname(), nameOne);
			assertEquals(server.getNextMessage().getSenderNickname(), nameTwo);
			assertFalse(server.hasNextMessage());
			
		
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Tests if the clients are able to receive messages coming from the server
	 */
	@Test
	public void serverToClientsMessage(){
		Order orderOne = Order.createBuyOrder(nameOne, "EDP", 20, 1);
		
		constructServerClient();
		
		assertFalse(clientOne.hasNextMessage());
		assertFalse(clientTwo.hasNextMessage());
		
		server.sendOrder(nameOne, orderOne);
		server.sendError(nameTwo, "Erro");
		
		try {
			Thread.sleep(500);
			assertTrue(clientOne.hasNextMessage());
			assertTrue(clientTwo.hasNextMessage());
			assertEquals(clientOne.getNextMessage().getType(), ClientSideMessage.Type.ORDER);
			assertEquals(clientTwo.getNextMessage().getType(), ClientSideMessage.Type.ERROR);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Tests if the server is able to disconnect the clients successfully
	 */
	@Test
	public void serverDisconnectClients(){
		constructServerClient();
		try {
			
			Thread.sleep(500);
			assertTrue(server.clientIsConnected(nameOne));
			assertTrue(server.clientIsConnected(nameTwo));
			
			server.disconnectClient(nameOne);
			server.disconnectClient(nameTwo);
			
			Thread.sleep(500);
			assertFalse(server.clientIsConnected(nameOne));
			assertFalse(server.clientIsConnected(nameTwo));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		
		
	}
	
	/**
	 * Test if the clients can disconnect from the server succesfully
	 */
	@Test
	public void clientsDisconnectFromServer(){
		constructServerClient();
		try {
			
			Thread.sleep(500);
			assertTrue(clientOne.isConnected());
			assertTrue(clientTwo.isConnected());
			
			clientOne.disconnect();
			clientTwo.disconnect();
			
			Thread.sleep(500);
			assertFalse(clientOne.isConnected());
			assertFalse(clientTwo.isConnected());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}

}
